package org.irri.smta.ui.bean;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.irri.smta.domain.Role;
import org.irri.smta.domain.User;
import org.irri.smta.service.IRoleService;
import org.irri.smta.service.IUserService;
import org.irri.smta.util.BeanUtils;
import org.irri.smta.util.PasswordUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Named("userTableBean")
@ViewScoped
public class UserTableBean extends TableBeanBase<User> {

	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = LoggerFactory
			.getLogger(UserTableBean.class);

	private static final String VIEW_NAME = "useradmin";

	@Inject
	@Named("userService")
	private IUserService<User, Long> userService;

	@Inject
	@Named("roleService")
	private IRoleService<Role, Long> roleService;

	private List<User> userList = new ArrayList<User>();
	private User newUser = new User();
	private User selectedUser = new User();
	private Boolean validPassword = false;
	private Integer passwordStrength = 0;
	private BeanUtils beanUtils = new BeanUtils();

	/**
	 * Constructor.
	 */
	public UserTableBean() {
		super();
		setViewName(VIEW_NAME);
	}

	/**
	 * Initialize table bean after instantiation and injection by loading
	 * the data and setting default values to properties.
	 */
	@PostConstruct
	public void init() {
		LOGGER.debug("Initialize " + UserTableBean.class.getName());
		
		newUser = new User();
		newUser.setRole(roleService.getDefaultRole());

		selectedUser = new User();
		selectedUser.setRole(roleService.getDefaultRole());

		validPassword = false;
		passwordStrength = 0;
	}
	
	/**
	 * Destroy the user table bean by deallocating property values.
	 */
	@PreDestroy
	private void destroy() {
		LOGGER.debug("Cleanup " + UserTableBean.class.getName());
		userList.clear();
		newUser = null;
		selectedUser = null;
	}

	/**
	 * Returns the new app user.
	 * 
	 * @return {@link User}
	 */
	public User getNewUser() {
		LOGGER.debug("getNewUser(): " + newUser);
		return newUser;
	}

	/**
	 * Sets the new app user
	 * 
	 * @param user {@link User}
	 */
	public void setNewUser(User user) {
		LOGGER.debug("setNewUser(User user): " + user);
		if (user != null) {
			this.newUser = user;
			validPassword = PasswordUtils.isValid(newUser.getPassword());
		}
	}

	public User getSelectedUser() {
		LOGGER.debug("getSelectedUser(): " + selectedUser);
		return selectedUser;
	}

	public void setSelectedUser(User user) {
		LOGGER.debug("Set selected app user: " + user);
		if (user != null) {
			this.selectedUser = user;
			validPassword = PasswordUtils.isValid(selectedUser.getPassword());
		}
	}

	/**
	 * Returns the {@link List} of {@link User}.
	 * 
	 * @return {@link List} of {@link User}
	 */
	public List<User> getUserList() {
		LOGGER.debug("getUserList()");
		return userList;
	}

	/**
	 * Sets the {@link List} of {@link User}.
	 * 
	 * @param userList
	 *            {@link List} of {@link User}.
	 */
	public void setUserList(List<User> userList) {
		LOGGER.debug("setUserList(List<User> userList): " + userList);
		if (userList != null) {
			this.userList = userList;
		}
	}

	@Override
	public User getRowData(String rowKey) {
		LOGGER.debug("getRowData(String rowKey): " + rowKey);
		for (User user : userList) {
			if (user.getId().toString().equals(rowKey)) {
				return user;
			}
		}
		return null;
	}

	@Override
	public Object getRowKey(User user) {
		LOGGER.debug("getRowKey(User user): " + user);
		return user.getId();
	}

	public Boolean getValidPassword() {
		LOGGER.debug("getValidPassword(): " + validPassword);
		return validPassword;
	}

	public void setValidPassword(Boolean validPassword) {
		LOGGER.debug("setValidPassword(Boolean validPassword): "
				+ validPassword);
		if (validPassword != null) {
			this.validPassword = validPassword;
		}
	}

	public Integer getPasswordStrength() {
		LOGGER.debug("getPasswordStrength(): " + passwordStrength);
		return passwordStrength;
	}

	public void setPasswordStrength(Integer passwordStrength) {
		LOGGER.debug("setPasswordStrength(Integer passwordStrength): "
				+ passwordStrength);
		if (passwordStrength != null) {
			this.passwordStrength = passwordStrength;
		}
	}

	private void updateAllValidPasswords() {
		LOGGER.debug("updateAllValidPasswords()");
		for (User user : userList) {
			user.setValidPassword(PasswordUtils.isValid(user.getPassword()));
		}
	}

	private void updateValidPassword(User user) {
		LOGGER.debug("updateValidPassword(User user): " + user);
		if (user != null) {
			user.setValidPassword(PasswordUtils.isValid(user.getPassword()));
		}
	}

	private void updateAllPasswordStrengths() {
		LOGGER.debug("updateAllPasswordStrengths()");
		for (User user : userList) {
			user.setPasswordStrength(PasswordUtils.getStrength(user
					.getPassword()));
		}
	}

	private void updatePasswordStrength(User user) {
		LOGGER.debug("updateAllPasswordStrengths(): " + user);
		if (user != null) {
			user.setPasswordStrength(PasswordUtils.getStrength(user
					.getPassword()));
		}
	}

	private void updatePasswordFeaturesInList(Long id) {
		LOGGER.debug("updatePasswordFeaturesInList(Long id): " + id);
		if (id != null) {
			for (User user : userList) {
				if (user.getId().longValue() == id.longValue()) {
					updateValidPassword(user);
					updatePasswordStrength(user);
				}
			}
		}
	}

	private User save(User user) {
		LOGGER.debug("save(User user): " + user);
		if (user != null) {
			try {
				return userService.create(user);
			} catch (Exception e) {
				LOGGER.error(getMessageProviderService().getMessage(
						"MSG_ERROR_SAVE_USER"));
				return null;
			}
		} else {
			LOGGER.error(getMessageProviderService().getMessage(
					"MSG_ERROR_SAVE_NO_USER"));
			return null;
		}
	}

	public void saveNew() {
		LOGGER.debug("saveNew(): " + newUser);
		if (newUser != null) {
			if (save(newUser) != null) {
				updateValidPassword(newUser);
				updatePasswordStrength(newUser);
				userList.add(0, newUser);
				refreshGlobalBean();
				newUser = new User();
			}
		}
	}

	private User update(User user) {
		LOGGER.debug("update(User user): " + user);
		if (user != null) {
			try {
				return userService.update(user);
			} catch (Exception e) {
				LOGGER.error(getMessageProviderService().getMessage(
						"MSG_ERROR_UPDATE_USER"));
				return null;
			}
		} else {
			LOGGER.error(getMessageProviderService().getMessage(
					"MSG_ERROR_UPDATE_NO_USER"));
			return null;
		}
	}

	public void updateSelected() {
		LOGGER.debug("updateSelected(): " + selectedUser);
		if (selectedUser != null) {
			if (update(selectedUser) != null) {
				updatePasswordFeaturesInList(selectedUser.getId());
				refreshGlobalBean();
			}
		}
	}

	private User delete(User user) {
		LOGGER.debug("delete(User user): " + user);
		if (user != null) {
			try {
				return userService.delete(user.getId());
			} catch (Exception e) {
				LOGGER.error(getMessageProviderService().getMessage(
						"MSG_ERROR_DELETE_USER"));
				return null;
			}
		} else {
			LOGGER.error(getMessageProviderService().getMessage(
					"MSG_ERROR_DELETE_NO_USER"));
			return null;
		}
	}

	public void deleteSelected() {
		LOGGER.debug("deleteSelected(): " + selectedUser);
		if (selectedUser != null) {
			if (delete(selectedUser) != null) {
				userList.remove(selectedUser);
				setStateEnabled(false);
				refreshGlobalBean();
			}
		}
	}

	@Override
	public Boolean addDisabled() {
		Boolean status = beanUtils.getSessionUser().getRole().getId().longValue() == 1;
		return !status;
	}

	@Override
	public Boolean editDisabled() {
		Boolean status = beanUtils.getSessionUser().getRole().getId().longValue() == 1;
		if (status && isStateEnabled()) {
			return false;
		}
		return true;
	}

	@Override
	public Boolean deleteDisabled() {
		Boolean status = beanUtils.getSessionUser().getRole().getId().longValue() == 1;
		if (status && isStateEnabled()) {
			return false;
		}
		return true;
	}

	@Override
	public void loadData() {
		LOGGER.debug("loadData()");
		userList = new ArrayList<User>();
		List<User> list = userService.findAllOrdered();
		userList.addAll(list);
		updateAllValidPasswords();
		updateAllPasswordStrengths();
	}

	public void refreshGlobalBean() {
		getGlobalBean().loadUserList();
	}

}
